/*
 * Copyright (c) [2020] Zhang Yansen.All rights reserved.
 *
 * use-async is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

/**
 * 这不是一个 hook
 */


// 已绑定列表
// 记录原始绑定内容
let originFunc = {}

 /**
  * 
  * @param {*} fn  method or function body
  * @param {*} handler  fn will be bound to handler
  */
 export default function(fn, handler) {
  if (typeof fn !== 'string' && typeof fn !== 'function') {
    throw new Error('[useAsync] param fn must be a function or string');
  }

  let _resolve, _reject;

  const idle = new Promise((resolve, reject) => {
    _resolve = resolve;
    _reject = reject;
  })

  // fn 有可能只是函数名称
  const fnName = typeof fn === 'string' ? fn : undefined;

  // 如果传入过来一个对象, 那么 fnName 是其一个属性
  const component = typeof handler === 'object' ?  handler : undefined;

  if (!originFunc[component]) {
    originFunc[component] = {}
  }

  // 第二个参数也可以是一个 setter
  const setter = typeof handler === 'function' ? handler : undefined;

  // 先去查找原始函数 因为重复 bind 会失效
  let realFn = originFunc[component][fnName]
  if (!realFn) {
    // 如果 fnName 是 component 的一个属性, 那么真正的函数就是这个属性的 value
    realFn = component && fnName ? component[fnName] : fn;
    // 原始函数会被缓存在 originFunc 中
    originFunc[component] = {
      ...originFunc[component],
      [fnName]: realFn,
    }
  }

  // 封装转入的函数
  const wrapFn = realFn.bind(component || this, { next: _resolve, cancel: _reject });
  
  // 封装的函数替换掉
  if (component && fnName) {
    component[fnName] = wrapFn
    component[`${fnName}Cancel`] = _reject
  }

  // 也可以通过 setter 传递出去
  if (setter) {
    setter(wrapFn, _reject)
  }

  return idle;
}
